package org.song.filter.certification;

import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import org.song.cache.UserRoleCache;
import org.song.exception.MyAuthenticationException;
import org.song.mapper.UserMapper;
import org.song.model.entity.RoleEntity;
import org.song.model.security.MyUserDetails;
import org.song.model.entity.UserEntity;
import org.song.service.RoleService;
import org.song.util.BCryptPasswordEncoderUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author song
 * @date 2022/3/9 17:24
 **/
@Service(value = "myUserDetailsServiceImpl")
@Slf4j
public class MyUserDetailsServiceImpl implements UserDetailsService {

    @Autowired(required = true)
    @Qualifier(value = "userMapper")
    private UserMapper userMapper;

    @Autowired( required = true )
    @Qualifier( value = "bCryptPasswordEncoderUtil")
    private BCryptPasswordEncoderUtil bCryptPasswordEncoderUtil;

    @Autowired( required = true )
    @Qualifier( value = "userRoleCacheImpl")
    private UserRoleCache userRoleCache;

    @Autowired( required = true )
    @Qualifier( value = "roleServiceImpl" )
    private RoleService roleService;

    /**
     * 根据用户名获取用户（封装信息到自定义MyUserDetails）
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据用户名查询用户信息
        final UserEntity userEntity = userMapper.getUserByUsername(username);
        Assert.isTrue(Objects.nonNull(userEntity), () -> {
            log.error("用户： " + username + "不存在！");
            return new UsernameNotFoundException("用户： " + username + "不存在！");
        });
        // 根据用户名从缓存中查询用户角色，缓存失效从DB取出写回缓存 TODO： 缓存穿透
        final Set<RoleEntity> roleEntitySet = Optional.ofNullable( userRoleCache.getUserRoleList( username ) ).orElseGet( () -> {
            final Set<RoleEntity> roleSetByUserName = roleService.getRoleSetByUserName(username);
            log.info("当前用户：" + username + "缓存角色信息过期DB取出写回缓存");
            userRoleCache.setUserRoleList( username , roleSetByUserName );
            return roleSetByUserName;
            });
        //TODO: 用户角色集合暂时存储角色Id
        // springSecurity的用户角色集合
        List<SimpleGrantedAuthority> springSecurityRoleIdList = roleEntitySet.stream()
                // 根据角色Id生成springSecurity自带角色实例
                .map( ( roleEntity ) -> new SimpleGrantedAuthority( Objects.toString( roleEntity.getId() ) ))
                .collect( Collectors.toList() );
        return new MyUserDetails( username , userEntity.getPassword() , userEntity.getDataStatus() , springSecurityRoleIdList );
    }

    /**
     * 根据用户名和密码校验身份
     * @param username
     * @param password
     * @return
     */
    public boolean checkUsernameAndPassword(String username, String password) {
        final UserEntity existingUserEntity = userMapper.getUserByUsername(username);
        Assert.isTrue( Objects.nonNull(existingUserEntity) , () -> new MyAuthenticationException("当前用户不存在： " + username) );
        return bCryptPasswordEncoderUtil.matches( password, existingUserEntity.getPassword());
    }




}
